#ifndef ARCH_SEGMENT_HEADER
#define ARCH_SEGMENT_HEADER

#include <lib/type.h>
#include <arch/page.h>

// gdt descript attribute filied
#define SEG_ATTRIBUTE_SYSSEGMENT 0x00
#define SEG_ATTRIBUTE_COMMONSEG 0x01
#define SEG_ATTRIBUTE_DPL0 0x00
#define SEG_ATTRIBUTE_DPL1 0x02
#define SEG_ATTRIBUTE_DPL2 0x04
#define SEG_ATTRIBUTE_DPL3 0x06
#define SEG_ATTRIBUTE_PRESENT 0x08
#define SEG_ATTRIBUTE_AVL 0x10
#define SEG_ATTRIBUTE_LMODE 0x20
#define SEG_ATTRIBUTE_32BITSOPMODE 0x40
#define SEG_ATTRIBUTE_4KBGRAN 0x80

// define segment descript type
#define SEG_TYPE_LDT 0x2
#define SEG_TYPE_TASKGATE 0x5
#define SEG_TYPE_TSSFREE 0x9
#define SEG_TYPE_TSSBUSY 0xB
#define SEG_TYPE_CALLGATE 0xC
#define SEG_TYPE_INTGATE 0xE
#define SEG_TYPE_TRAPGATE 0xF

// define code segment descript type filed
#define SEG_CODE_TYPE_ACCESS 0x1
#define SEG_CODE_TYPE_EXE 0x8
#define SEG_CODE_TYPE_CONFROM 0xC
#define SEG_CODE_TYPE_READ 0xA

// define data segment descript type filed
#define SEG_DATA_TYPE_READ 0x0
#define SEG_DATA_TYPE_ACCESS 0x1
#define SEG_DATA_TYPE_WRITE 0x2
#define SEG_DATA_TYPE_EXPANDDOWN 0x4

// gdt address and limit
#define GDT_ADDRESS 0x8F0000
#define GDT_VADDRESS PAGE_HIGH_BASE + GDT_ADDRESS
#define GDT_LIMIT 0x7FF

// seg sel define
#define SEG_SEL_KERNEL_CODE (1 << 3 | DPL_0 << 0)
#define SEG_SEL_KERNEL_STACK (2 << 3 | DPL_0 << 0)
#define SEG_SEL_KERNEL_DATA (2 << 3 | DPL_0 << 0)
#define SEG_SEL_USER_CODE (3 << 3 | DPL_3 << 0)
#define SEG_SEL_USER_DATA (4 << 3 | DPL_3 << 0)
#define SEG_SEL_USER_STACK (4 << 3 | DPL_3 << 0)
#define SEG_SEL_TSS (5 << 3 | DPL_0 << 0)

#define DPL_0 0
#define DPL_1 1
#define DPL_2 2
#define DPL_3 3

// sel mask
#define SEL_INDEX_MASK(sel) ((uint8_t)((sel >> 3) & 0x1F))
#define SEL_DPL_MASK(sel) ((uint8_t)((sel >> 1) & 0x3))
#define SEL_TI_MASK(sel) ((uint8_t)(sel & 0x1))

void SegmentDescriptInit();
void SegmentDescriptInstall(uint32_t base, uint32_t limit, uint8_t attr, uint8_t type, uint8_t sel);

#endif